package com.xtool.livewallpaper.transparent

import android.app.Activity
import android.content.Context
import android.graphics.ImageFormat
import android.hardware.Camera
import android.opengl.GLSurfaceView
import android.util.AttributeSet
import android.view.SurfaceHolder
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import com.xtool.livewallpaper.R
import com.xtool.livewallpaper.util.ToastUtil
import com.xtool.livewallpaper.video.GLES30WallpaperRenderer
import kotlin.math.abs

class CameraView constructor(context: Context, attrs: AttributeSet? = null) :
    GLSurfaceView(context, attrs), SurfaceHolder.Callback, LifecycleObserver {
    private var mCamera: Camera? = null
    private var isFront = false
    private var mRenderer: GLES30WallpaperRenderer? = null
    private var mLifecycle: Lifecycle? = null

    init {
        holder.addCallback(this)
        createRender()
    }

    fun bindLifecycle(lifecycle: Lifecycle) {
        mLifecycle = lifecycle
        lifecycle.addObserver(this)
    }

    private fun createRender() {
        setEGLContextClientVersion(3)
        mRenderer = GLES30WallpaperRenderer(context)
        preserveEGLContextOnPause = true
        setRenderer(mRenderer!!)
        renderMode = RENDERMODE_CONTINUOUSLY
        mRenderer!!.createSurfaceTexture()
    }

    private fun createCamera() {
        release()
        try {
            val cameraId =
                if (isFront) Camera.CameraInfo.CAMERA_FACING_FRONT else Camera.CameraInfo.CAMERA_FACING_BACK
            mCamera = Camera.open(cameraId).apply {
                setDisplayOrientation(90)
                setPreviewDisplay(holder)
            }
            updateCameraSize()
            mCamera?.startPreview()
        } catch (e: Exception) {
            ToastUtil.show(R.string.camera_is_using)
            (context as? Activity)?.finish()
        }
    }

    fun release() {
        mCamera?.stopPreview()
        mCamera?.release()
        mCamera = null
    }

    fun setIsFront(isFront: Boolean) {
        this.isFront = isFront
        createCamera()
    }

    private fun getBestSize(parameters: Camera.Parameters): Camera.Size? {
        val sizes = parameters.supportedPreviewSizes
        var bestSize: Camera.Size? = null
        val uiRatio = 1f * height / width
        var minRatio = uiRatio
        for (previewSize in sizes) {
            val cameraRatio = previewSize.width.toFloat() / previewSize.height
            val offset = abs(cameraRatio - uiRatio)
            if (offset < minRatio) {
                minRatio = offset
                bestSize = previewSize
            }
            if (uiRatio == cameraRatio) {
                bestSize = previewSize
                break
            }
        }
        return bestSize
    }

    private fun updateCameraSize() {
        try {
            val parameters: Camera.Parameters = mCamera?.parameters ?: return
            val bestSize = getBestSize(parameters) ?: return
            parameters.setPreviewSize(bestSize.width, bestSize.height)
            parameters.setPictureSize(bestSize.width, bestSize.height)
            parameters.previewFormat = ImageFormat.NV21
            val focusModes: List<String> = parameters.supportedFocusModes
            if (focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
                parameters.focusMode = Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE
            }
            mCamera?.parameters = parameters
            mRenderer?.setScreenSize(width, height)
            mRenderer?.setVideoSizeAndRotation(bestSize.width, bestSize.height, 0)
        } catch (e: java.lang.Exception) {
        }
    }

    override fun surfaceCreated(holder: SurfaceHolder) {
        createCamera()
    }

    override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
        super.onLayout(changed, left, top, right, bottom)
        updateCameraSize()
    }

    override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
        updateCameraSize()
    }

    override fun surfaceDestroyed(holder: SurfaceHolder) {
        release()
    }

    override fun onDetachedFromWindow() {
        release()
        super.onDetachedFromWindow()
    }
}